package com.maben.s9002.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * master节点数据库配置
 */
@Configuration
@EnableTransactionManagement
@MapperScan(
        basePackages = DataSourceMybatisConfig.PACKAGE_MAPPER,
        sqlSessionFactoryRef = "masterSqlSessionFactory"
)
public class DataSourceMybatisConfig {
    public static final String PACKAGE_MAPPER = "com.maben.s9002.mapper";
    private static final String MAPPER_LOCATION = "classpath*:com/maben/s9002/**/*Mapper.xml";
    private static final String PACKAGE_POJO = "com.maben.s9002.pojo";


    @Value("${spring.datasource.druid.url}")
    private String url;
    @Value("${spring.datasource.druid.password}")
    private String password;
    @Value("${spring.datasource.druid.username}")
    private String username;
    @Value("${spring.datasource.druid.driverClassName}")
    private String driverClassName;
    @Value("${spring.datasource.druid.initial-size}")
    private int initialSize;
    @Value("${spring.datasource.druid.min-idle}")
    private int minIdle;
    @Value("${spring.datasource.druid.max-active}")
    private int maxActive;
    @Value("${spring.datasource.druid.max-wait}")
    private int maxWait;
    @Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
    private int timeBetweenEvictionRunsMillis;
    @Value("${spring.datasource.druid.validation-query}")
    private String validationQuery;
    @Value("${spring.datasource.druid.test-while-idle}")
    private boolean testWhileIdle;
    @Value("${spring.datasource.druid.test-on-borrow}")
    private boolean testOnBorrow;
    @Value("${spring.datasource.druid.test-on-return}")
    private boolean testOnReturn;

    /**
     * 配置数据库【数据源】
     */
    @Bean(name = "mybatisDataSource")
    @Primary //多个数据源配置一个默认使用的
    public DataSource masterDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        //连接基础参数
        druidDataSource.setUrl(url);
        druidDataSource.setPassword(password);
        druidDataSource.setUsername(username);
        druidDataSource.setDriverClassName(driverClassName);
        //连接池设置
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setValidationQuery(validationQuery);
        druidDataSource.setTestWhileIdle(testWhileIdle);
        druidDataSource.setTestOnBorrow(testOnBorrow);
        druidDataSource.setTestOnReturn(testOnReturn);
        //支持批量更新设置
        List<Filter> filterList = new ArrayList<>();
        filterList.add(wallFilter());
        filterList.add(statFilter());
        druidDataSource.setProxyFilters(filterList);
        return druidDataSource;
    }

    @Value("${spring.datasource.druid.filter.wall.config.multi-statement-allow}")
    private boolean filterWallMultiStatementAllow;

    /**
     * wall（防SQL注入）
     */
    public WallFilter wallFilter() {
        WallConfig config = new WallConfig();
        WallFilter wallFilter = new WallFilter();
        config.setMultiStatementAllow(filterWallMultiStatementAllow);//允许一次执行多条语句
        wallFilter.setConfig(config);
        return wallFilter;
    }

    @Value("${spring.datasource.druid.filter.stat.log-slow-sql}")
    private boolean filterStatLogSlowSql;
    @Value("${spring.datasource.druid.filter.stat.slow-sql-millis}")
    private long filterStatSlowSqlMillis;
    @Value("${spring.datasource.druid.filter.stat.merge-sql}")
    private boolean filterStatMergeSql;

    /**
     * stat（监控统计）
     */
    public StatFilter statFilter() {
        StatFilter statFilter = new StatFilter();
        statFilter.setSlowSqlMillis(filterStatSlowSqlMillis);
        statFilter.setLogSlowSql(filterStatLogSlowSql);
        statFilter.setMergeSql(filterStatMergeSql);
        return statFilter;
    }

    /**
     * 配置【声明事务管理器】
     */
    @Bean(name = "mybatisTransactionManager")
    public DataSourceTransactionManager mybatisTransactionManager() {
        return new DataSourceTransactionManager(masterDataSource());
    }

    /**
     * 创建工厂 整合mybatis-plus
     */
    @Bean(name = "masterSqlSessionFactory")
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("mybatisDataSource") DataSource mybatisDataSource)
            throws Exception {
        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        sessionFactory.setDataSource(mybatisDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(DataSourceMybatisConfig.MAPPER_LOCATION));
        sessionFactory.setTypeAliasesPackage(DataSourceMybatisConfig.PACKAGE_POJO);
        //驼峰处理
        final MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        sessionFactory.setConfiguration(mybatisConfiguration);
        return sessionFactory.getObject();
    }

}
